package com.awesumgames.awesum;

import static java.lang.Math.sqrt;
import static java.lang.Math.sin;
import static java.lang.Math.cos;

import java.util.Locale;

import javax.vecmath.Vector3f;

import static com.awesumgames.awesum.AwesumGlobal.Awesum.degToRad;

public final class Vector3 extends Vector3f {
	
	public Vector3() {
		x = y = z = 0f;
	}
	public Vector3(Vector3 v2) {
		x = v2.x;
		y = v2.y;
		z = v2.z;
	}
	public Vector3(float x, float y, float z) {
		this.x = x; this.y = y; this.z = z;
	}
	public Vector3(double x, double y, double z) {
		this.x = (float)x; this.y = (float)y; this.z = (float)z;
	}
	public Vector3(Vector3f v2) {
		x = v2.x;
		y = v2.y;
		z = v2.z;
	}
	
	public String toString() {
		return String.format(Locale.US, "(%f, %f, %f)", x, y, z);
	}
	
	public Vector3 copy() {
		return new Vector3(this);
	}
	
	public boolean equals(Vector3 v2) {
		return x == v2.x && y == v2.y && z == v2.z;
	}
	public boolean equals(float nx, float ny, float nz) {
		return x == nx && y == ny && z == nz;
	}

	public Vector3 set(Vector3 v2) {
		this.x = v2.x; this.y = v2.y; this.z = v2.z;
		return this;
	}
	public Vector3 set2(float x, float y, float z) {
		this.x = x; this.y = y; this.z = z;
		return this;
	}

	public Vector3 add(Vector3 v2) {
		x += v2.x; y += v2.y; z += v2.z;
		return this;
	}
	public Vector3 add(float s) {
		x += s; y += s; z += s;
		return this;
	}
	public Vector3 add(float ax, float ay, float az) {
		x += ax; y += ay; z += az;
		return this;
	}
	public Vector3 subtract(Vector3 v2) {
		x -= v2.x; y -= v2.y; z -= v2.z;
		return this;
	}
	public Vector3 multiply(float s) { //Scalar multiply
		x *= s; y *= s; z *= s;
		return this;
	}
	public Vector3 multiply(Vector3 v2) { //Scalar multiply individual components
		x *= v2.x; y *= v2.y; z *= v2.z;
		return this;
	}
	public Vector3 divide(float s) { //Scalar divide
		x /= s; y /= s; z /= s;
		return this;
	}
	public Vector3 divide(Vector3 v2) { //Scalar divide individual components
		x /= v2.x; y /= v2.y; z /= v2.z;
		return this;
	}
	public Vector3 mod(float s) { //Scalar modulo
		x %= s; y %= s; z %= s;
		return this;
	}
	public Vector3 negate2() {
		x=-x;y=-y;z=-z; //2x fast as multiply(-1)
		return this;
	}
	public float magnitude() {
		return (float)sqrt(magnitudeSq());
	}
	public float magnitudeSq() {
		return x*x + y*y + z*z;
	}
	
	public Vector3 abs() {
		x = Math.abs(x);
		y = Math.abs(y);
		z = Math.abs(z);
		return this;
	}
	
	public Vector3 normalize2() {
		return divide(magnitude());
	}
	public float dot(Vector3 v2) {
		return x*v2.x + y*v2.y + z*v2.z;
	}
	public Vector3 cross(Vector3 v2) {
		return new Vector3(y*v2.z - z*v2.y, z*v2.x - x*v2.z, x*v2.y - y*v2.x);
	}
	public float distFrom(Vector3 v2) {
		return (float)sqrt(distSqFrom(v2));
	}
	public float distSqFrom(Vector3 v2) {
		float dx = x-v2.x, dy = y-v2.y, dz = z-v2.z;
		return dx*dx + dy*dy + dz*dz;
	}
	
	
	public Vector3 rotateX(float a) {
		a *= degToRad;
		
		double ny = cos(a) * y + sin(a) * z;
		double nz = -sin(a) * y + cos(a) * z;
		
		y = (float)ny;
		z = (float)nz;
		return this;
	}

	public Vector3 rotateY(float a) {
		a *= degToRad;
		
		double nx = cos(a) * x - sin(a) * z;
		double nz = sin(a) * x + cos(a) * z;
		
		x = (float)nx;
		z = (float)nz;
		return this;
	}

	public Vector3 rotateZ(float a) {
		a *= degToRad;
		
		double nx = cos(a) * x + sin(a) * y;
		double ny = -sin(a) * x + cos(a) * y;
		
		x = (float)nx;
		y = (float)ny;
		return this;
	}

	public Vector3 rotate(Vector3 v2) { //This might encounter a gimbal lock problem
		if (v2.x != 0f) rotateX(v2.x);
		if (v2.y != 0f) rotateY(v2.y);
		if (v2.z != 0f) rotateZ(v2.z);
		return this;
	}
}
